home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / shell / csh535src.lha / comm1.c next >
Encoding:
C/C++ Source or Header  |  1993-12-22  |  50.3 KB  |  2,289 lines

  1. /*
  2.  * COMM1.C
  3.  *
  4.  * Matthew Dillon, August 1986
  5.  *
  6.  * Version 2.07M by Steve Drew 10-Sep-87
  7.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  8.  * Version 5.00L by Urban Mueller 17-Feb-91
  9.  * Version 5.20L by Andreas M. Kirchwitz (Fri, 13 Mar 1992)
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14.  
  15. /* comm1.c */
  16. static void display_file(char *filestr);
  17. static int search_file( long mask, char *s, char *fullpath );
  18. static int rm_file    ( long mask, char *s, char *fullpath );
  19. static int quicksearch(char *name, int nocasedep, char *pattern);
  20. static void setsystemtime(struct DateStamp *ds);
  21. static int found( char *lstart, int lnum, int loffs, char *name, char left );
  22.  
  23. void lformat( char *s, char *d, FILEINFO *info );
  24.  
  25. extern int has_wild;
  26.  
  27. int
  28. do_sleep( void )
  29. {
  30.     int i;
  31.  
  32.     if (ac == 2) for (i=atoi(av[1]); i>0 && !CHECKBREAK(); i--) Delay(50);
  33.     return 0;
  34. }
  35.  
  36. /* AMK: if you change this, you must change do_chmod() also!! */
  37. int
  38. do_protect( void )
  39. {
  40.     static char flags[]="DEWRAPSH";
  41.     char *s, *p;
  42.     long setmask=0, clrmask=0xFF, mask;
  43.     int  i, mode=0, stat;
  44.     DPTR *dp;
  45.  
  46.     for (s=strupr(av[--ac]); *s; s++) {
  47.         if (*s=='=') { mode=0; continue; }
  48.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  49.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  50.  
  51.         if (*s=='X') *s='E';
  52.         if (p=index(flags, *s)) {
  53.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  54.             if( mode==1 ) setmask|= 1<<(p-flags);
  55.             if( mode==2 ) clrmask|= 1<<(p-flags);
  56.         } else {
  57.             ierror(av[ac],500);
  58.             return 20;
  59.         }
  60.     }
  61.  
  62.     for (i=1; i<ac; i++) {
  63.         if( (dp=dopen(av[i],&stat))) {
  64.             mask = dp->fib->fib_Protection ^ 0x0F;
  65.             mask&=~clrmask;
  66.             mask|= setmask;
  67.             dclose(dp);
  68.             if( !SetProtection( av[i], mask ^ 0x0F))
  69.                 pError(av[i]);
  70.         } else
  71.             pError(av[i]);
  72.     }
  73.     return 0;
  74. }
  75.  
  76. /* AMK: same as do_protect, but flags now as first argument */
  77. int
  78. do_chmod( void )
  79. {
  80.     static char flags[]="DEWRAPSH";
  81.     char *s, *p;
  82.     long setmask=0, clrmask=0xFF, mask;
  83.     int  i, mode=0, stat;
  84.     DPTR *dp;
  85.  
  86.     for (s=strupr(av[1]); *s; s++) {       /* AMK: changed */
  87.         if (*s=='=') { mode=0; continue; }
  88.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  89.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  90.  
  91.         if (*s=='X') *s='E';
  92.         if (p=index(flags, *s)) {
  93.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  94.             if( mode==1 ) setmask|= 1<<(p-flags);
  95.             if( mode==2 ) clrmask|= 1<<(p-flags);
  96.         } else {
  97.             ierror(av[1],500);     /* AMK: changed */
  98.             return 20;
  99.         }
  100.     }
  101.  
  102.     for (i=2; i<ac; i++) {                 /* AMK: changed */
  103.         if( (dp=dopen(av[i],&stat))) {
  104.             mask = dp->fib->fib_Protection ^ 0x0F;
  105.             mask&=~clrmask;
  106.             mask|= setmask;
  107.             dclose(dp);
  108.             if( !SetProtection( av[i], mask ^ 0x0F))
  109.                 pError(av[i]);
  110.         } else
  111.             pError(av[i]);
  112.     }
  113.     return 0;
  114. }
  115.  
  116. int
  117. do_filenote( void )
  118. {
  119.     DPTR *dp;
  120.     char *note;
  121.     int i, stat;
  122.  
  123.     if( options&1 ) {
  124.         for( i=1; i<ac && !dobreak(); i++ )
  125.             if( dp=dopen( av[i], &stat )) {
  126.                 printf( "%-12s %s\n", av[i],dp->fib->fib_Comment );
  127.                 dclose( dp );
  128.             }
  129.     } else {
  130.         note=av[--ac];
  131.         for (i=1; i<ac; i++) if (!SetComment(av[i], note)) pError(av[i]);
  132.     }
  133.     return 0;
  134. }
  135.  
  136. int
  137. do_cat( void )
  138. {
  139.     FILE *fi;
  140.     int lctr, i, docr=0;
  141.     char buf[256], *l;
  142.  
  143.     prepscroll(0);
  144.     if (ac<=1) {
  145.         if (has_wild) { printf("No files matching\n"); return 20; }
  146.         lctr=0;
  147.         while (fgets(buf,256,stdin) && !dobreak()) {
  148.             if (options) printf("%4d ",++lctr);
  149.             quickscroll();
  150.             l=buf+strlen( buf )-1; docr=1;
  151.             if( l>=buf && *l=='\n' ) docr=0;
  152.             fputs(buf,stdout);
  153.         }
  154.     } else {
  155.         for (i=1; i<ac; i++)
  156.             if (fi = fopen (av[i], "r")) {
  157.                 lctr=0;
  158.                 while (fgets(buf,256,fi) && !dobreak()) {
  159.                     if (options&1) printf("%4d ",++lctr);
  160.                     quickscroll();
  161.                     l=buf+strlen( buf )-1; docr=1;
  162.                     if( l>=buf && *l=='\n' ) docr=0;
  163.                     fputs(buf,stdout); fflush(stdout);
  164.                 }
  165.                 fclose (fi);
  166.             } else
  167.                 pError(av[i]);
  168.     }
  169.     if( docr && isconsole(Output()))
  170.         putchar('\n');
  171.     return 0;
  172. }
  173.  
  174.  
  175.  
  176. char *add_simple_device(char *list,char *dev)
  177. {
  178.     char *new = NULL;
  179.  
  180.     if (list) {
  181.         if (new = malloc(strlen(dev)+strlen(list)+2)) {        /* null byte + \n */
  182.             strcpy(new,list);
  183.             strcat(new,dev);
  184.             strcat(new,"\n");
  185.             free(list);
  186.         }
  187.         else
  188.             new = list;
  189.     }
  190.     else {
  191.         if (new = malloc(strlen(dev)+2)) {            /* null byte + \n */
  192.             strcpy(new,dev);
  193.             strcat(new,"\n");
  194.         }
  195.     }
  196.  
  197.     return(new);
  198. }
  199.  
  200.  
  201.  
  202. void
  203. get_drives(char *buf)
  204. {
  205.     struct DosList *dl;
  206.     ULONG flags = LDF_DEVICES|LDF_READ;
  207.     char devname[256];
  208.     char **dev_list=NULL;
  209.     long i,dev_num=0;
  210.  
  211.     buf[0]=0;
  212.     if (dl=LockDosList(flags)) {
  213.         while (dl=NextDosEntry(dl,flags)) {
  214.             if (dl->dol_Task) {
  215.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  216.                 strcat(devname,":");
  217.                 add_array_list(&dev_list,&dev_num,devname);
  218.             }
  219.         }
  220.         UnLockDosList(flags);
  221.     }
  222.  
  223.     QuickSort(dev_list,dev_num);
  224.  
  225.     for(i=0; i<dev_num; i++) {
  226.         if (IsFileSystem(dev_list[i])) {
  227.             if (buf[0])
  228.                 strcat(buf,"\240");
  229.             strcat(buf,dev_list[i]);
  230.         }
  231.     }
  232.  
  233.     free_array_list(dev_list,dev_num);
  234. }
  235.  
  236. static char infobuf[100];
  237. static char namebuf[32];  /* AMK: old size was 12, too small for drive names */
  238.  
  239.  
  240. /* AMK: find last occurence of a character in a string */
  241. char *strlast(char *s,char c)
  242. {
  243.   char *p=NULL;
  244.   while(*s) {
  245.     if(*s==c)
  246.       p=s;
  247.     s++;
  248.   }
  249.   return(p);
  250. }
  251.  
  252. #if 0
  253. /* AMK: just another itok() */
  254. char *
  255. itok42( int i )
  256. {
  257.     static char buf[16], which;
  258.     char *exp=" KMG", *ptr= buf+(which=8-which);
  259.  
  260.     if (i<=10238976) {
  261.         sprintf( ptr,"%d%c",(i/1024),'K');
  262.         return ptr;
  263.     }
  264.  
  265.     do
  266.         i=(i+512)/1024, exp++;
  267.     while( i>1024 );
  268.     sprintf( ptr,"%d%c",i,*exp);
  269.  
  270.     return ptr;
  271. }
  272. #endif
  273.  
  274. char *
  275. drive_name( char *name )
  276. {
  277.     struct DosList *dl;
  278.     struct MsgPort *proc= (struct MsgPort *)DeviceProc( (void*)name );
  279.     ULONG flags = LDF_DEVICES|LDF_READ;
  280.     char devname[256];
  281.     char **dev_list=NULL;
  282.     long i,dev_num=0;
  283.  
  284.     /* AMK: we want no self-modifying code */
  285.     strncpy( namebuf, name, 31 );   /* AMK: 30 chars device name + ':' */
  286.     namebuf[31] = '\0';             /* AMK: null-terminated */
  287.     if (dl=LockDosList(flags)) {
  288.         while (dl=NextDosEntry(dl,flags)) {
  289.             if (dl->dol_Task) {
  290.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  291.                 strcat(devname,":");
  292.                 add_array_list(&dev_list,&dev_num,devname);
  293.             }
  294.         }
  295.         UnLockDosList(flags);
  296.     }
  297.  
  298.     QuickSort(dev_list,dev_num);
  299.  
  300.     for(i=0; i<dev_num; i++) {
  301.         if (IsFileSystem(dev_list[i])) {
  302.             if ((struct MsgPort *)DeviceProc(dev_list[i])==proc)
  303.                 strcpy(namebuf,dev_list[i]);
  304.         }
  305.     }
  306.  
  307.     free_array_list(dev_list,dev_num);
  308.  
  309.     return namebuf;
  310. }
  311.  
  312. int
  313. do_info( void )
  314. {
  315.     struct DosList *dl;
  316.     ULONG flags = LDF_DEVICES|LDF_READ;
  317.     char devname[256];
  318.     char **dev_list=NULL;
  319.     long i,dev_num=0;
  320.  
  321.     if (options&2)
  322.         puts("Unit     Size  Block  Type   Used   Free Full Errs  Status    Name");
  323.     else
  324.         puts("Unit     Size  Bytes  Used Blk/Byte-Free Full Errs  Status    Name");
  325.  
  326.     if( ac==1 ) {
  327.         if (dl=LockDosList(flags)) {
  328.             while (dl=NextDosEntry(dl,flags)) {
  329.                 if (dl->dol_Task) {
  330.                     BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  331.                     strcat(devname,":");
  332.                     add_array_list(&dev_list,&dev_num,devname);
  333.                 }
  334.             }
  335.             UnLockDosList(flags);
  336.         }
  337.  
  338.         QuickSort(dev_list,dev_num);
  339.  
  340.         for(i=0; !dobreak() && i<dev_num; i++) {
  341.             if (IsFileSystem(dev_list[i])) {
  342.                 oneinfo(dev_list[i],0);
  343.             }
  344.         }
  345.  
  346.         free_array_list(dev_list,dev_num);
  347.     }
  348.     else {
  349.         for( i=1; i<ac; i++ )
  350.             oneinfo( drive_name( av[i] ), 0 );
  351.     }
  352.  
  353.     return 0;
  354. }
  355.  
  356.  
  357.  
  358. /* these defines are new in OS 3.x */
  359. #ifndef ID_FASTDIR_DOS_DISK
  360. #define ID_FASTDIR_DOS_DISK (0x444F5304L)
  361. #endif
  362. #ifndef ID_FASTDIR_FFS_DISK
  363. #define ID_FASTDIR_FFS_DISK (0x444F5305L)
  364. #endif
  365.  
  366.  
  367.  
  368. /* AMK: new mode==6 to suppress output if disk is not present */
  369. char *
  370. oneinfo( char *name, int mode )
  371. {
  372.     struct InfoData *info;
  373.     struct DevProc *devproc;
  374.     struct DeviceList *dl;
  375.     BPTR lock;
  376.     long size, free, freebl, blocks;
  377.     char buf[130], *state, *type;
  378.     char *fmt="%s\240%s\240%d\240%d\240%d\240%s\240%d%%\240%d\240%s\240%s";
  379.  
  380.     Myprocess->pr_WindowPtr = (APTR)(-1);
  381.  
  382.     if (!name) name="";
  383.  
  384.     if (mode<=1 || mode>=5)
  385.         strcpy(infobuf,"");
  386.     else
  387.         strcpy(infobuf,"0");
  388.  
  389.     info=(struct InfoData *)SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  390.  
  391.     if (devproc=GetDeviceProc(name,NULL)) {
  392.         if (DoPkt(devproc->dvp_Port,ACTION_DISK_INFO,MKBADDR(info),NULL,NULL,NULL,NULL)==DOSTRUE) {
  393.             BOOL go_on = FALSE;
  394.             char *spclfmt;
  395. #if 0
  396.             NameFromLock(lock, buf, 128L);
  397.             if (p=strlast(buf,':')) *p = '\0';
  398.             /* AMK: we want the last occurence of ':', not the first;
  399.                     ':' and '/' are legal path name components !!
  400.             if (p=index(buf,':')) *p = '\0';
  401.             */
  402. #endif
  403.             switch (mode) {
  404.                 case 0:
  405.                     if (options&1)
  406.                         spclfmt = "";
  407.                     else
  408.                         spclfmt = "%-7s %s\n";
  409.                     break;
  410.                 case 1:
  411.                     spclfmt = "%s\240%s\n";
  412.                     break;
  413.                 case 2:
  414.                 case 3:
  415.                 case 4:
  416.                     spclfmt = "0";
  417.                     break;
  418.                 case 5:
  419.                     spclfmt = "";
  420.                     break;
  421.                 default:
  422.                     spclfmt = "";
  423.                     break;
  424.             }
  425.  
  426.             switch (info->id_DiskType) {
  427.                 case ID_UNREADABLE_DISK:
  428.                     sprintf(infobuf,spclfmt,name,"Unreadable disk");
  429.                     break;
  430.                 case ID_NOT_REALLY_DOS:
  431.                     sprintf(infobuf,spclfmt,name,"Not a DOS disk");
  432.                     break;
  433.                 case ID_KICKSTART_DISK:
  434.                     sprintf(infobuf,spclfmt,name,"Kickstart disk");
  435.                     break;
  436.                 case (0x42555359L):  /* 'BUSY' */
  437.                     sprintf(infobuf,spclfmt,name,"Disk is busy");
  438.                     break;
  439.                 case ID_NO_DISK_PRESENT:
  440.                     sprintf(infobuf,spclfmt,name,"No disk present");
  441.                     break;
  442.                 default:
  443.                     sprintf(infobuf,spclfmt,name,"Unknown disk type");
  444.                     go_on = TRUE;
  445.                     break;
  446.             }
  447.  
  448.             if (go_on && (lock=Lock(name,ACCESS_READ))) {
  449.                 UnLock(lock);
  450.                 /* note:  we call Lock() to be sure that the volume is readable */
  451.  
  452.                 switch(info->id_DiskType) {
  453.                     case ID_MSDOS_DISK:       type=" MSDOS"; break;
  454.                     case ID_DOS_DISK:         type="   OFS"; break;
  455.                     case ID_FFS_DISK:         type="   FFS"; break;
  456.                     case ID_INTER_DOS_DISK:   type="IN/OFS"; break;
  457.                     case ID_INTER_FFS_DISK:   type="  INTL"; break;
  458.                     case ID_FASTDIR_DOS_DISK: type="DC/OFS"; break;
  459.                     case ID_FASTDIR_FFS_DISK: type="  DCFS"; break;
  460.                     default:                  type="   n/a"; break;
  461.                 }
  462.  
  463.                 strcpy(buf,"n/a");
  464.                 if (dl = (struct DeviceList *)BADDR(info->id_VolumeNode))
  465.                     BtoCStr(buf,dl->dl_Name,100L);
  466.  
  467.                 switch(info->id_DiskState) {
  468.                     case ID_WRITE_PROTECTED: state="Read Only "; break;
  469.                     case ID_VALIDATED:       state="Read/Write"; break;
  470.                     case ID_VALIDATING:      state="Validating"; break;
  471.                     default:                 state="Unknown   "; break;
  472.                 }
  473.  
  474. #if 0
  475.                 size   = (info->id_NumBlocks + 2) * info->id_BytesPerBlock;
  476. #endif
  477.                 size   = info->id_NumBlocks * info->id_BytesPerBlock;
  478.                 freebl = info->id_NumBlocks - info->id_NumBlocksUsed;
  479.                 free   = freebl * info->id_BytesPerBlock;
  480.                 blocks = info->id_NumBlocks;
  481. #if 0
  482.                 printf("percents: %s... %ld, %ld, %ld, %ld, %ld\n",name,
  483.                     ((info->id_NumBlocksUsed+2) * 100)/blocks,
  484.                     (info->id_NumBlocksUsed * 100)/(blocks+2),
  485.                     (((info->id_NumBlocksUsed * 1000)/blocks)+5)/10,
  486.                     ((((info->id_NumBlocksUsed+2) * 1000)/blocks)+5)/10,
  487.                     (((info->id_NumBlocksUsed * 1000)/(blocks+2))+5)/10
  488.                 );
  489. #endif
  490.  
  491.                 if (mode==0 && options&2) {
  492.                     fmt="%-7s%6s%6d %6s %6s %6s %3d%%%4d  %10s %s\n";
  493.                     sprintf(infobuf,fmt,
  494.                         name,
  495.                         itok( size ),
  496.                         info->id_BytesPerBlock,
  497.                         type,
  498.                         itok( info->id_NumBlocksUsed*info->id_BytesPerBlock ),
  499.                         itok( free ),
  500.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  501. #if 0
  502.                         (blocks) ? ((info->id_NumBlocksUsed * 1000)/blocks + 5) / 10 : 0,
  503. #endif
  504.                         info->id_NumSoftErrors,
  505.                         state,
  506.                         buf);
  507.                 }
  508.                 else if (mode<=1) {
  509.                     if (mode==0) fmt="%-7s%6s%6d%7d%7d %6s%4d%%%4d  %s %s\n";
  510.                     sprintf(infobuf,fmt,
  511.                         name,
  512.                         itok( size ),
  513.                         info->id_BytesPerBlock,
  514.                         info->id_NumBlocksUsed,
  515.                         freebl,
  516.                         itok( free ),
  517.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  518.                         info->id_NumSoftErrors,
  519.                         state,
  520.                         buf);
  521.                 }
  522.                 else if (mode==2) sprintf(infobuf,"%d",free);
  523.                 else if (mode==3) sprintf(infobuf,"%d",freebl);
  524.                 else if (mode==4) sprintf(infobuf,"%s",itok(free));
  525.                 else if (mode==5) sprintf(infobuf,"%s:",buf);
  526.             }
  527.         }
  528.         else
  529.             pError(name);
  530.         FreeDeviceProc(devproc);
  531.     }
  532.  
  533. #if 0
  534.     else {
  535.         if (mode==1) {
  536.             struct MsgPort *devtask;
  537.             sprintf(infobuf,"%s\240No disk present\n",name);
  538.             if (devtask=(struct MsgPort *)DeviceProc(name)) {
  539.                 struct InfoData *infodata;
  540.                 infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  541.                 if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  542.                     switch (infodata->id_DiskType) {
  543.                     case ID_UNREADABLE_DISK:
  544.                         sprintf(infobuf,"%s\240Unreadable disk\n",name);
  545.                         break;
  546.                     case ID_NOT_REALLY_DOS:
  547.                         sprintf(infobuf,"%s\240Not a DOS disk\n",name);
  548.                         break;
  549.                     case ID_KICKSTART_DISK:
  550.                         sprintf(infobuf,"%s\240Kickstart disk\n",name);
  551.                         break;
  552.                     case (0x42555359L):  /* 'BUSY' */
  553.                         sprintf(infobuf,"%s\240Busy\n",name);
  554.                         break;
  555.                     case ID_NO_DISK_PRESENT:
  556.                     default:
  557.                         sprintf(infobuf,"%s\240No disk present\n",name);
  558.                         break;
  559.                     }
  560.                 }
  561.                 FreeMem(infodata,sizeof(struct InfoData));
  562.             }
  563.         }
  564.         else if (mode==0) {
  565.             if (options&1) {
  566.                 sprintf(infobuf,"");
  567.             }
  568.             else {
  569.                 struct MsgPort *devtask;
  570.                 sprintf(infobuf,"%-7s No disk present\n",name);
  571.                 if (devtask=(struct MsgPort *)DeviceProc(name)) {
  572.                     struct InfoData *infodata;
  573.                     infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  574.                     if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  575.                         switch (infodata->id_DiskType) {
  576.                         case ID_UNREADABLE_DISK:
  577.                             sprintf(infobuf,"%-7s Unreadable disk\n",name);
  578.                             break;
  579.                         case ID_NOT_REALLY_DOS:
  580.                             sprintf(infobuf,"%-7s Not a DOS disk\n",name);
  581.                             break;
  582.                         case ID_KICKSTART_DISK:
  583.                             sprintf(infobuf,"%-7s Kickstart disk\n",name);
  584.                             break;
  585.                         case (0x42555359L):  /* 'BUSY' */
  586.                             sprintf(infobuf,"%-7s Disk is busy\n",name);
  587.                             break;
  588.                             case ID_NO_DISK_PRESENT:
  589.                         default:
  590.                             sprintf(infobuf,"%-7s No disk present\n",name);
  591.                             break;
  592.                         }
  593.                     }
  594.                     FreeMem(infodata,sizeof(struct InfoData));
  595.                 }
  596.             }
  597.         }
  598.         else if (mode==5) sprintf(infobuf,"");
  599.         else              sprintf(infobuf,"0");
  600.     }
  601. #endif
  602.  
  603.     if (mode==0) printf("%s",infobuf);
  604.  
  605.     FreeMem(info,sizeof(struct InfoData));
  606.     Myprocess->pr_WindowPtr = (APTR)o_noreq;
  607.  
  608.     return infobuf;
  609. }
  610.  
  611.  
  612. /* things shared with display_file */
  613.  
  614. #define DIR_SHORT 0x1
  615. #define DIR_FILES 0x2
  616. #define DIR_DIRS  0x4
  617. #define DIR_NOCOL 0x8
  618. #define DIR_NAMES 0x10
  619. #define DIR_HIDE  0x20
  620. #define DIR_LEN   0x40
  621. #define DIR_TIME  0x80
  622. #define DIR_BACK  0x100
  623. #define DIR_UNIQ  0x200
  624. #define DIR_IDENT 0x400
  625. #define DIR_CLASS 0x800
  626. #define DIR_QUIET 0x1000
  627. #define DIR_AGE   0x2000
  628. #define DIR_VIEW  0x4000
  629. #define DIR_NOTE  0x8000
  630. #define DIR_PATH  0x10000
  631. #define DIR_LFORM 0x20000
  632. #define DIR_BOT   0x40000
  633. #define DIR_TOP   0x80000
  634. #define DIR_LINK  0x100000
  635.  
  636. static char *lastpath = NULL;
  637. static int filecount, dircount, col, colw, wwidth;
  638. static long bytes, blocks;
  639.  
  640. /* the args passed to do_dir will never be expanded */
  641.  
  642. extern expand_err;
  643. extern int w_width;
  644.  
  645. static struct DateStamp Stamp;
  646. static char *LineBuf, *LinePos, LastWasDir, *LFormat, _LFormat[80], NoTitles;
  647.  
  648. int
  649. do_dir( void )
  650. {
  651.     int i=1, c, eac, reverse, nump=ac, retcode=0;
  652.     char **eav=NULL, **av1=NULL, **av2=NULL, inter=isconsole(Output());
  653.     char linebuf[1024];
  654.     int (*func)(), ac1, ac2, factor=0;
  655.  
  656.     LineBuf=LinePos=linebuf;
  657.     LastWasDir=NoTitles=0;
  658.     colw=-1;
  659.  
  660.     LFormat=_LFormat;
  661.  
  662.     if( options&DIR_CLASS ) options|=DIR_IDENT;
  663.     if( !(options & (DIR_FILES | DIR_DIRS))) options|= DIR_FILES | DIR_DIRS;
  664.  
  665.     DateStamp( &Stamp );
  666.  
  667.     col = filecount = dircount = bytes = blocks = 0L;
  668.     if (lastpath) free(lastpath);
  669.     lastpath=NULL;
  670.  
  671.     wwidth=77;
  672.     if( inter )
  673.         wwidth=w_width;
  674.  
  675.     if( options&DIR_SHORT )
  676.         strcpy(LFormat," %-18n%19m");
  677.     else if( options&DIR_PATH )
  678.         strcpy(LFormat," %-50p %7s %d"), NoTitles=1;
  679.     else {
  680.         if ( options&DIR_NOTE )
  681.             strcpy(LFormat,"  %-30n %o");
  682.         else if ( options&DIR_LINK )
  683.             strcpy(LFormat,"  %-30n %L");
  684.         else {
  685. #if 1
  686.             strcpy(LFormat,"  ");
  687. #else
  688.             strcpy(LFormat,"  %-30n ");
  689. #endif
  690.             if( options&DIR_HIDE )
  691.                 strcat(LFormat, "%e");
  692.             strcat(LFormat,"%c%I%f ");
  693.             if( options&DIR_VIEW )
  694.                 strcat(LFormat,"%10v  ");
  695.             else
  696.                 strcat(LFormat,"%8s  ");
  697. #if 0
  698.             if( !(options&DIR_QUIET) )
  699.                 strcat(LFormat,options&DIR_VIEW?"%5b ":"%4b ");
  700. #endif
  701.             if( options&DIR_IDENT )
  702.                 strcat(LFormat,"%k");
  703.             else if( options&DIR_AGE )
  704.                 strcat(LFormat,"%a");
  705.             else
  706.                 strcat(LFormat,"%d %t");
  707. #if 1
  708.             strcat(LFormat,"  %N");
  709. #endif
  710.         }
  711.     }
  712.  
  713.     if( options&DIR_LFORM ) {
  714.         char *fmtstr;
  715.         if (fmtstr=get_var(LEVEL_SET,v_dirformat)) {
  716.             strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  717.             LFormat[79]=0;
  718.         }
  719.         else if (ac>1)
  720.             LFormat=av[i++];
  721.         else {
  722.             show_usage(NULL);
  723.             return 20;
  724.         }
  725.     }
  726.  
  727.     if( ac == i) ++nump, av[i]="";
  728.     if( options&DIR_UNIQ) {
  729.         if( ac-i!=2 )  { show_usage(NULL); return 20; }
  730.         i=0, nump=3;
  731.     }
  732.  
  733.     prepscroll(0);
  734.     for( ; i<nump && !CHECKBREAK(); ++i ) {
  735.         if( options&DIR_UNIQ ) {
  736.             switch( i ) {
  737.                 case 0: av1=expand( av[ac-2], &ac1 );
  738.                         av2=expand( av[ac-1], &ac2 );
  739.                         eav=without( av1, ac1, av2, ac2, &eac, 1 );
  740.                         break;
  741.                 case 1: printf("\nCommon files\n");
  742.                         eav=and( av1, ac1, av2, ac2, &eac, 1 );
  743.                         break;
  744.                 case 2: printf("\n");
  745.                         eav=without( av2, ac2, av1, ac1, &eac, 1 );
  746.                         break;
  747.             }
  748.             col = filecount = dircount = bytes = blocks = 0L;
  749.             if (lastpath) free(lastpath);
  750.             lastpath=NULL;
  751.  
  752.         /* AMK: enhanced handling of non-matching patterns */
  753.         } else if (!(eav = expand(av[i], &eac))) {
  754.             if (IoError) {
  755.                 ierror(av[i],IoError);
  756.                 retcode=5;
  757.             }
  758. #if 0
  759.             else {
  760.                 if (strlen(av[i])>0)
  761.                     fprintf(stderr,"%s: No match.\n",av[i]);
  762.             }
  763. #endif
  764.             continue;
  765.         }
  766.  
  767.         reverse= ( options&DIR_BACK ) ? 1 : 0;
  768.         func=cmp;
  769.         if( options & DIR_TIME) func=datecmp_csh;
  770.         if( options & DIR_LEN ) func=sizecmp;
  771.         if( options & DIR_CLASS)func=classcmp;
  772.         if( options & DIR_BOT ) factor=-99999999;
  773.         if( options & DIR_TOP ) factor= 99999999;
  774.         DirQuickSort(eav, eac, func, reverse, factor);
  775.         for(c=0; c<eac && !CHECKBREAK(); ++c) {
  776.             if( options & DIR_HIDE ) {
  777.                 char *b=FilePart(eav[c]);
  778.                 int  l=strlen(b)-5;
  779.                 FILEINFO *info =(FILEINFO *)eav[c] - 1;
  780.                 if(*b=='.'|| (l>=0 && !strcmp(b+l,".info"))||(info->flags&128))
  781.                     continue;
  782.             }
  783.             if (options & DIR_NAMES) {
  784.                 FILEINFO *info = (FILEINFO *)eav[c] - 1;
  785.                 if(options&(info->size<0 ? DIR_DIRS: DIR_FILES))
  786.                     puts(eav[c]);
  787.             } else
  788.                 display_file(eav[c]);
  789.         }
  790.  
  791.         if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  792.  
  793.         if( LastWasDir )
  794.             printf(o_lolite), LastWasDir=0;
  795.  
  796.         if (options&DIR_UNIQ || (filecount>1 && i==nump-1)) {
  797.             blocks += filecount-dircount; /* account for dir blocks */
  798.             quickscroll();
  799.             printf(" %ld Blocks, %s Bytes used in %d files\n",
  800.                 blocks, itoa(bytes), filecount);
  801.         }
  802.         if( options&DIR_UNIQ )
  803.             free(eav);
  804.         else
  805.             free_expand (eav);
  806.     }
  807.     if (lastpath) free(lastpath);
  808.     lastpath=NULL;
  809.  
  810.     if( options&DIR_UNIQ )
  811.         free_expand( av1 ), free_expand( av2 );
  812.  
  813.     return retcode;
  814. }
  815.  
  816. static int MultiCol=-1;
  817.  
  818. static char
  819. pathcomp( char *s1, char *s2 )
  820. {
  821.     char ret, *t, c;
  822.  
  823.     t=FilePart( s2 ); c=*t; *t=0;
  824.     ret=stricmp( s1, s2 );
  825.     *t=c;
  826.     return ret;
  827. }
  828.  
  829. static void
  830. display_file( char *filestr )
  831. {
  832.     /* struct InfoData *id=AllocMem( sizeof(struct InfoData), 0); */
  833.     int isadir, len, collen;
  834.     char sc, *base, buf[1024], *hilite;
  835.     FILEINFO *info;
  836.     BPTR thislock;
  837.  
  838.     base=FilePart(filestr);
  839.     sc = *base;
  840.     *base = 0;
  841.     /* if (thislock==NULL) return; */
  842.     if( !NoTitles ) {
  843.         if( !lastpath || pathcomp( filestr, lastpath)) {
  844.             if(!(thislock=Lock(filestr,SHARED_LOCK)))
  845.                 return;
  846.             if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  847.             quickscroll();
  848.             NameFromLock(thislock, buf, 256);
  849.             if( LastWasDir )
  850.                 printf(o_lolite), LastWasDir=0;
  851.             printf("Directory of %s\n", buf );
  852.             /* Info( thislock, id ); */
  853.             /* itok((id->id_NumBlocks-id->id_NumBlocksUsed)*id->id_BytesPerBlock));*/
  854.             /* FreeMem( id, sizeof(struct InfoData)); */
  855.             lastpath = salloc(256);
  856.             strcpy(lastpath,filestr);
  857.             /*lastpath=filestr;*/
  858.             UnLock(thislock);
  859.         }
  860.     }
  861.     *base    = sc;
  862.  
  863.     info   = (FILEINFO *)filestr - 1;
  864.     isadir = info->size<0;
  865.  
  866.     if( !(options & (isadir ? DIR_DIRS : DIR_FILES)))
  867.         return;
  868.  
  869.     hilite="";
  870.     if (isadir!=LastWasDir && !(options & DIR_NOCOL))
  871.         hilite=isadir ? o_hilite : o_lolite, LastWasDir=isadir;
  872.  
  873.     lformat(LFormat, buf, info);
  874.  
  875.     if( MultiCol==-1 ) {
  876.         quickscroll();
  877.         printf("%s%s",hilite,buf);
  878.     } else {
  879.         len=strlen(buf);
  880.         if( col+len>wwidth ) {
  881.             quickscroll();
  882.             puts(LineBuf);
  883.             LinePos=LineBuf; col=0;
  884.         }
  885.         if( MultiCol )
  886.             colw=MultiCol;
  887.         else if( colw==-1 )
  888.             colw=len;
  889.         collen= (len+colw-1)-(len+colw-1)%colw;
  890.         col+=collen;
  891.         LinePos+=sprintf(LinePos,"%s%-*s",hilite,collen,buf);
  892.     }
  893.  
  894.     if(info->size>0)
  895.         bytes  += info->size;
  896.     blocks += info->blocks;
  897.     filecount++;
  898. }
  899.  
  900. static char linebuf[1024];
  901. static long dlen, dblocks;
  902.  
  903. static int
  904. count( long mask, char *s, char *path )
  905. {
  906.     FIB *fib=(FIB*)s-1;
  907.     dlen+=fib->fib_Size;
  908.     dblocks+=fib->fib_NumBlocks+1;
  909.     return 0;
  910. }
  911.  
  912.  
  913. /* code contribution by Carsten Heyl, modified by AMK */
  914. void ReadSoftLink(char *path, char *buf, int buflen)
  915. {
  916.     BPTR MyLock;
  917.     BPTR DevLock;
  918.     LONG Err, l;
  919.     UBYTE *bs;
  920.     struct MsgPort *port;
  921.  
  922.     if (buflen>9)
  923.         strcpy(buf,"<unknown>");
  924.     else
  925.         buf[0] = '\0';    /* just terminate buffer. alternative ? */
  926.  
  927.     if ( (l=strlen(path)) > 254 )
  928.         return;
  929.  
  930.     if (!(bs=AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC)))
  931.         return;
  932.  
  933.     bs[255] = '\0';
  934.  
  935.     /* build BCPL string */
  936.     bs[0] = l;
  937.     memcpy(&bs[1], path, l+1);
  938.  
  939.     /* GetDeviceProc or DeviceProc? */
  940.     if (!(port = DeviceProc(path))) {
  941.         FreeMem(bs,256);
  942.         return;
  943.     }
  944.  
  945.     DevLock = (BPTR)IoErr();
  946.  
  947.     MyLock = DoPkt(port,ACTION_LOCATE_OBJECT,DevLock,MKBADDR(bs),
  948.                 ACCESS_READ,NULL,NULL);
  949.     Err = IoErr();
  950.  
  951.     if (!MyLock && (Err==ERROR_IS_SOFT_LINK)) {
  952. #if 0
  953.         ReadLink(port,DevLock,(UBYTE *)path,(UBYTE *)buf,buflen);
  954. #else
  955.         DoPkt(port,ACTION_READ_LINK,DevLock,(LONG)path,(LONG)buf,buflen,NULL);
  956. #endif
  957.     }
  958.  
  959.     if (MyLock) UnLock(MyLock);
  960.     FreeMem(bs,256);
  961. }
  962.  
  963.  
  964. void
  965. lformat( char *s, char *d, FILEINFO *info )
  966. {
  967.     long mi=0;
  968.     char buf[1024], *w, *t, *class;
  969.     DPTR *dp;
  970.     int stat, i, form, sign, cut, size=info->size;
  971.     char *(*func)(int num);
  972.  
  973.     MultiCol=-1;
  974.     while( *s ) {
  975.         if( *s!='%' ) { *d++=*s++; continue; }
  976.         sign=1; form=0; cut=0; s++;
  977.         if( *s=='-' ) s++, sign=-1;
  978.         if( *s=='.' ) s++, cut=1;
  979.         while( *s>='0' && *s<='9' ) form=10*form+*s++-'0';
  980.         w=buf; w[0]=0; w[1]=0;
  981.         switch( *s ) {
  982.         case 'p': strcpy(w,(char *)(info+1));             break;
  983.         case 'b': sprintf(w,size>=0 ? "%d":"", info->blocks); break;
  984.         case 's': sprintf(w,size>=0 ? "%d":"<Dir>",size); break;
  985.         case 'i': *w= size>=0 ? '-' : 'd';                break;
  986.         case 'r':
  987.         case 'u':
  988.             if( *s=='r' ) func=itoa; else func=itok;
  989.             strcpy( w,size>=0 ? (*func)(size) : "<Dir>");
  990.             break;
  991.         case 'n':
  992.         case 'q':
  993.             strcpy(w,FilePart((char *)(info+1)));
  994.             if( *s=='q' && size<0 ) strcat(w,"/");
  995.             break;
  996.         case 'l':
  997.             if( info->flags & INFO_COMMENT ) *w='\n';
  998.             break;
  999.         case 'c':
  1000.             *w= info->flags & INFO_COMMENT ? 'c' : '-';
  1001.             break;
  1002.         case 'e':
  1003.             *w= info->flags & INFO_INFO ? 'i' : '-';
  1004.             break;
  1005.         case '+':
  1006.             *w= info->flags & INFO_INFO ? '+' : ' ';
  1007.             break;
  1008.         case 'L':
  1009.         case 'N':
  1010.             if (*s=='N')
  1011.                 strcpy(w,FilePart((char *)(info+1)));
  1012.             else
  1013.                 strcpy(w,"");
  1014.             if (info->type==ST_SOFTLINK) {
  1015.                 strcat(w," -> ");
  1016.                 ReadSoftLink((char *)(info+1),w+strlen(w),256);
  1017.             }
  1018.             else if (info->type==ST_LINKDIR || info->type==ST_LINKFILE) {
  1019.                 BPTR lock;
  1020.                 if (lock=Lock((char *)(info+1),ACCESS_READ)) {
  1021.                     strcat(w," -> ");
  1022.                     NameFromLock(lock,w+strlen(w),256);
  1023.                     UnLock(lock);
  1024.                 }
  1025.             }
  1026.             break;
  1027.         case 'I':
  1028.             switch (info->type) {
  1029.                 case ST_SOFTLINK:
  1030.                     *w='S';
  1031.                     break;
  1032.                 case ST_LINKDIR:
  1033.                 case ST_LINKFILE:
  1034.                     *w='H';
  1035.                     break;
  1036.                 case ST_PIPEFILE:
  1037.                     *w='P';
  1038.                     break;
  1039.                 default:
  1040.                     *w='-';
  1041.                     break;
  1042.             }
  1043.             break;
  1044.         case 'f':
  1045.             for (i=7; i>=0; i--)
  1046.                 *w++ = (info->flags^15) & (1L<<i) ? "hsparwed"[7-i] : '-';
  1047.             *w=0;
  1048.             break;
  1049.         case 'a':
  1050.             if( Stamp.ds_Days!=0 ) {
  1051.                 mi =Stamp.ds_Days*1440 + Stamp.ds_Minute;
  1052.                 mi-=info->date.ds_Days*1440 + info->date.ds_Minute;
  1053.             }
  1054.             sprintf(w,mi>=0?"%4d days %02d:%02d":"Future    ",
  1055.                       mi/1440,mi/60%60,mi%60);
  1056.             break;
  1057.         case 'o':
  1058.             if( dp=dopen( (char *)(info+1), &stat )) {
  1059.                 strcpy( w, dp->fib->fib_Comment );
  1060.                 dclose( dp );
  1061.             }
  1062.             break;
  1063.         case 'v':
  1064.         case 'w':
  1065.             if( *s=='v' ) func=itoa; else func=itok;
  1066.             dlen=dblocks=0;
  1067.             if( size<0 ) {
  1068.                 newrecurse( SCAN_DIR|SCAN_FILE|SCAN_RECURSE,
  1069.                             (char *)(info+1),count);
  1070.                 strcpy( w, (*func)(dlen));
  1071.                 info->size=size=dlen; info->blocks=dblocks;
  1072.             } else
  1073.                 strcpy( w, (*func)(size));
  1074.             break;
  1075.         case 'k':
  1076.             if( *info->class!=1 )
  1077.                 strcpy(w,info->class);
  1078.             else if( class=getclass((char *)(info+1)))
  1079.                 if( w=index(strncpy(w,class,50),0xA0) )
  1080.                     *w=0;
  1081.             break;
  1082.         case 'x':
  1083.         case 'd':
  1084.             sprintf(w,"%9s",dates(&info->date,*s=='x'));
  1085.             if(t=index(w,' ')) *t=0;
  1086.             break;
  1087.         case 't':
  1088.             sprintf(w,"%8s", next_word(dates(&info->date,0)));
  1089.             break;
  1090.         case 'm': MultiCol=form; form=0;      break;
  1091.         case '%': *w=*++s;                    break;
  1092.         case  0 : *w='%';                     break;
  1093.         default : *w='%';  *w++=*s; *w=0;     break;
  1094.         }
  1095.         if( cut ) buf[form]=0;
  1096.         *d=0; s++;
  1097.         d+=sprintf(d,sign<0?"%-*s":"%*s",form,buf);
  1098.     }
  1099.     if( MultiCol==-1 ) { *d++='\n'; }
  1100.     *d=0;
  1101. }
  1102.  
  1103.  
  1104.  
  1105. extern BOOL nologout;    /* defined in main.c */
  1106.  
  1107. int
  1108. do_quit( void )
  1109. {
  1110.     if (Src_stack) {
  1111.         Quit = 1;
  1112.         return(do_return());
  1113.     }
  1114.     if (!nologout) {
  1115.         if( exists("S:.logout"))
  1116.             execute("source S:.logout");
  1117.     }
  1118.     main_exit(0);
  1119.     return 0;
  1120. }
  1121.  
  1122. int
  1123. do_echo( void )
  1124. {
  1125.     char *args=compile_av(av,1,ac,' ',0);
  1126.     fprintf( (options&2)?stderr:stdout, (options&1)?"%s":"%s\n",args );
  1127.     free(args);
  1128.     return 0;
  1129. }
  1130.  
  1131.  
  1132. static int
  1133. breakcheckd(void)
  1134. {
  1135.     int ret=!o_nobreak && SetSignal(0L,0L) & SIGBREAKF_CTRL_D;
  1136.     if( ret )
  1137.         fprintf(stderr,"^D\n");
  1138.     return ret;
  1139. }
  1140.  
  1141. /* gets a line from file, joining lines if they end in '\' */
  1142.  
  1143. #define MAXLINE 512
  1144.  
  1145. static int
  1146. srcgets(char **buf, int *buflen, FILE *file)
  1147. {
  1148.     char *bufptr=*buf, *p, *new, concat=0, cont;
  1149.     int   totlen=0, len;
  1150.  
  1151.     do {
  1152.         if( totlen+MAXLINE > *buflen ) {
  1153.             new=salloc(*buflen *= 2);
  1154.             memcpy( new, *buf, 1+bufptr-*buf );
  1155.             bufptr+= new-*buf;
  1156.             free(*buf);
  1157.             *buf=new;
  1158.         }
  1159.         if (fgets(bufptr, MAXLINE, file)==NULL) {
  1160.             if( concat )
  1161.                 fprintf(stderr,"Source: missing '}'\n");
  1162.             else if (bufptr != *buf)
  1163.                 fprintf(stderr,"Source: file ends in '\\'\n");
  1164.             return -1;
  1165.         }
  1166.         len= strlen( bufptr );
  1167.         totlen+= len;
  1168.  
  1169.         cont=0;
  1170.  
  1171.         p=bufptr+len-1;
  1172.         if(  p>=bufptr && *p=='\n') *p--=0;
  1173.         if(  p< bufptr   ) ;
  1174.         else if( *p=='\\') *p--=0, cont=1;
  1175.         else if( *p=='{' ) concat++;
  1176.         else if( *p=='}' ) {
  1177.             if( concat>0 ) {
  1178.                 concat--;
  1179.                 if( concat ) *++p='\n';
  1180.             }
  1181.         } else if( concat ) *++p='\n';
  1182.         bufptr=++p;
  1183.     } while( cont || concat );
  1184.     *bufptr=0;
  1185.     return totlen;
  1186. }
  1187.  
  1188.  
  1189.  
  1190. int
  1191. do_source( char *str )
  1192. {
  1193.     FILE *fi;
  1194.     char *buf;
  1195.     ROOT *root;
  1196.     int  retcode, len, bufsize=512+MAXLINE;
  1197.     int j;
  1198.     char *ptr;
  1199.  
  1200.     if (Src_stack == MAXSRC) {
  1201.         ierror(NULL,217);
  1202.         return -1;
  1203.     }
  1204.  
  1205.     if ((fi = fopen (av[1], "r")) == 0)
  1206.         { pError(av[1]); return -1;    }
  1207.  
  1208.     push_locals(root=(ROOT *)salloc( sizeof(ROOT)));
  1209.     buf=salloc(bufsize);
  1210.  
  1211.     set_var(LEVEL_SET | LEVEL_LOCAL, v_passed, next_word(next_word(str)));
  1212.  
  1213.  
  1214.     /*
  1215.      * now create a bunch of positional parameters , $0, $1 etc
  1216.      */
  1217.     j = 0;
  1218.     ptr = next_word (str);
  1219.     while (*ptr) {
  1220.         char *var;
  1221.         char p[6];
  1222.         char npos[6];
  1223.  
  1224.         var = ptr;
  1225.         sprintf (p, "%d", j);
  1226.         /*
  1227.          * term var str
  1228.          */
  1229.         ptr = next_word (ptr);
  1230.  
  1231.         /* printf("%s\n" , ptr); */
  1232.  
  1233.         if (*ptr)
  1234.             *(ptr - 1) = '\0';
  1235.  
  1236.         set_var (LEVEL_SET | LEVEL_LOCAL, p, var);
  1237.         /*
  1238.          * now set up what should be $# ( number of positionals )
  1239.          */
  1240. #if 0
  1241.         sprintf (p, "_N");    /* should be "#" but csh barfs :( */
  1242. #endif
  1243.         sprintf (p, "#");    /* hackin' */
  1244.         sprintf (npos, "%d", j++);
  1245.         set_var (LEVEL_SET | LEVEL_LOCAL, p, npos);
  1246.     }
  1247.  
  1248.  
  1249.     Src_pos  [Src_stack] = 0;
  1250.     Src_abort[Src_stack] = 0;
  1251.     Src_base [Src_stack] = fi;
  1252.     Src_if[Src_stack]=If_stack;
  1253.     ++Src_stack;
  1254.     while ((len=srcgets(&buf, &bufsize, fi))>=0&& !dobreak()&& !breakcheckd()){
  1255.         Src_pos[Src_stack-1] += len;
  1256.         if (Verbose&VERBOSE_SOURCE && !forward_goto)
  1257.             if( Verbose&VERBOSE_HILITE )
  1258.                 fprintf(stderr,"%s)%s%s\n",o_hilite,buf,o_lolite);
  1259.             else
  1260.                 fprintf(stderr,")%s\n",buf);
  1261.         retcode=execute(buf);
  1262.         if( retcode>=o_failat || Src_abort[Src_stack-1] )
  1263.             break;
  1264.         retcode=0;
  1265.     }
  1266.     --Src_stack;
  1267.     if( If_stack>Src_if[Src_stack] )
  1268.         If_stack=Src_if[Src_stack], disable=If_stack && If_base[If_stack-1];
  1269.  
  1270.     if (forward_goto) ierror(NULL,501);
  1271.     forward_goto = 0;
  1272.     unset_level(LEVEL_LABEL+ Src_stack);
  1273.     unset_var(LEVEL_SET, v_gotofwd);
  1274.     unset_var(LEVEL_SET, v_passed);
  1275.     fclose (fi);
  1276.  
  1277.     pop_locals();
  1278.     free(buf);
  1279.     free(root);
  1280.  
  1281.     return retcode;
  1282. }
  1283.  
  1284. /* set process cwd name and $_cwd, if str != NULL also print it. */
  1285.  
  1286. void
  1287. set_cwd(void)
  1288. {
  1289.     char pwd[256];
  1290.  
  1291.     NameFromLock(Myprocess->pr_CurrentDir, pwd, 254);
  1292.     set_var(LEVEL_SET, v_cwd, pwd);
  1293.     /* put the current dir name in our CLI task structure */
  1294.     CtoBStr(pwd, Mycli->cli_SetName, 254);
  1295. }
  1296.  
  1297. int
  1298. do_pwd( void )
  1299. {
  1300.     set_cwd();
  1301.     puts( get_var( LEVEL_SET, v_cwd ));
  1302.     return 0;
  1303. }
  1304.  
  1305.  
  1306. /*
  1307.  * CD
  1308.  *
  1309.  * CD(str, 0)      -do CD operation.
  1310.  *
  1311.  */
  1312.  
  1313. extern int qcd_flag;
  1314.  
  1315. static char lastqcd[80];
  1316. static FILE *qcdfile;
  1317. static int  NumDirs;
  1318.  
  1319. static int
  1320. countfunc( long mask, char *file, char *fullpath )
  1321. {
  1322.     fprintf( qcdfile, "%s\n", fullpath );
  1323.     fprintf( stdout, "\r Directories: %d", ++NumDirs );
  1324.     fflush ( stdout );
  1325.     return 0;
  1326. }
  1327.  
  1328. int
  1329. do_cd(void)
  1330. {
  1331.     BPTR oldlock, filelock;
  1332.     char buf[100], *old, *str=av[1];
  1333.     int  i=1, repeat;
  1334.  
  1335.     if( options & 1 ) {
  1336.         if( !o_csh_qcd ) { fprintf(stderr,"$_qcd unset\n"); return 20; }
  1337.         if( !(qcdfile=fopen( o_csh_qcd, "w" )))
  1338.             { fprintf(stderr,"Can't open output\n"); return 20; }
  1339.         for( ; i<ac && !dobreak(); i++ ) {
  1340.             NumDirs=0;
  1341.             printf("%s\n",av[i]);
  1342.             newrecurse( SCAN_DIRENTRY | SCAN_RECURSE, av[i], countfunc );
  1343.             printf("\n");
  1344.         }
  1345.         fclose(qcdfile);
  1346.         return 0;
  1347.     }
  1348.  
  1349.     if ( !str || !(*str) ) {    /* old "!*str" causes enforcer hit! */
  1350.         printf("%s\n", get_var( LEVEL_SET, v_cwd ));
  1351.         return 0;
  1352.     }
  1353.  
  1354.     if (filelock=Lock(str,ACCESS_READ)) {
  1355.         lastqcd[0]=0;
  1356.         if (!isdir(str)) { UnLock(filelock); ierror(str,212); return 20; }
  1357.     } else {
  1358.         repeat= !strncmp( lastqcd, str, 79 );
  1359.         strncpy( lastqcd, str, 79);
  1360.  
  1361.         if( !quick_cd( buf, av[i], repeat) )
  1362.             { fprintf(stderr,"Object not found %s\n",str); return 20; }
  1363.         if (!(filelock=Lock(buf,ACCESS_READ)))
  1364.             { pError(buf); return 20; }
  1365.     }
  1366.     if (oldlock=CurrentDir(filelock)) UnLock(oldlock);
  1367.     if( !(old=get_var(LEVEL_SET, v_cwd)) )
  1368.         old="";
  1369.     set_var(LEVEL_SET, v_lcd, old);
  1370.     set_cwd();
  1371.  
  1372.     return 0;
  1373. }
  1374.  
  1375. char *
  1376. quick_cd( char *buf, char *name, int repeat )
  1377. {
  1378.     if( !o_csh_qcd || !exists(o_csh_qcd))
  1379.         return NULL;
  1380.     qcd_flag=repeat ? 2 : 1;
  1381.     strcpy(buf,name);
  1382.     if( quicksearch( o_csh_qcd, 1, buf)!=2 )
  1383.         return NULL;
  1384.     return buf;
  1385. }
  1386.  
  1387.  
  1388. /* AMK: mkdir now builds path to destination directory if neccessary */
  1389. int
  1390. do_mkdir( void )
  1391. {
  1392.     int i;
  1393.     BPTR lock;
  1394.     char *p,c;
  1395.  
  1396.     for (i=1; i<ac; ++i) {
  1397.  
  1398.         /* Are there any sub-directories to build? */
  1399.         if( options&1 && (p=strchr(av[i],'/'))) {
  1400.             do {
  1401.                 c = *p;
  1402.                 *p = '\0';
  1403.                 if (lock=CreateDir(av[i]))
  1404.                     UnLock(lock);
  1405.                 *p = c;
  1406.             } while(p=strchr(++p,'/'));
  1407.         }
  1408.  
  1409.         /* Okay, sub-directories should exist, now try normal mkdir. */
  1410.         if (exists(av[i]))
  1411.             ierror(av[i],203);
  1412.         else if (lock=CreateDir(av[i]))
  1413.             UnLock (lock);
  1414.         else
  1415.             pError(av[i]);
  1416.  
  1417.     }
  1418.  
  1419.     return 0;
  1420. }
  1421.  
  1422. int
  1423. do_mv( void )
  1424. {
  1425.     char *dest, buf[256];
  1426.     int dirflag, i, len;
  1427.  
  1428.     dirflag=isdir(dest=av[--ac]);
  1429.     if (ac>3 && !dirflag) { ierror(dest, 507); return (-1); }
  1430.     for (i=1; i<ac; ++i) {
  1431.         strcpy(buf, dest);
  1432.  
  1433.         /* source: remove trailing slash */
  1434.         if ((len=strlen(av[i]))>1 && av[i][len-1]=='/' && av[i][len-2]!=':' && av[i][len-2]!='/')
  1435.             av[i][len-1] = '\0';
  1436.  
  1437.         /* destination: remove trailing slash */
  1438.         if ((len=strlen(buf))>1 && buf[len-1]=='/' && buf[len-2]!=':' && buf[len-2]!='/')
  1439.             buf[len-1] = '\0';
  1440.  
  1441.         if (dirflag && stricmp(av[i],buf))
  1442.              AddPart(buf, FilePart(av[i]), 255L);
  1443.  
  1444.         if (Rename(av[i], buf)==0) {
  1445.             pError(av[i]);
  1446.             if (!(options&1))
  1447.                 return -1;
  1448.         }
  1449.         else {
  1450.             clear_archive_bit( buf );
  1451.             if (options&2) {
  1452.                 /*printf("Renaming %s as %s\n",av[i],buf);*/
  1453.                 printf(" %s...%s\n",av[i],dirflag?"moved":"renamed");
  1454.             }
  1455.         }
  1456.     }
  1457.     return 0;
  1458. }
  1459.  
  1460. static char *searchstring;
  1461. static char docr;
  1462.  
  1463. #if 0
  1464. int
  1465. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1466. {
  1467.     int  i;
  1468.     long mask= SCAN_FILE;
  1469.  
  1470.     if( options&1 )
  1471.         mask |= SCAN_RECURSE;
  1472.     if( dirsflag )
  1473.         mask |= SCAN_DIR;
  1474.  
  1475.     for ( i=1; i<ac && !dobreak(); ++i)
  1476.         if (isdir(av[i])) {
  1477.             if (options & 1)
  1478.                 newrecurse(mask, av[i], action);
  1479.             if (dirsflag)
  1480.                 (*action)(SCAN_DIR,av[i],av[i]);
  1481.         } else
  1482.             (*action)(SCAN_FILE,av[i],av[i]);
  1483.     if(docr) printf("\n"),docr=0;
  1484.     dobreak();
  1485.     return 0;
  1486. }
  1487. #endif
  1488.  
  1489. /* this is all_args() but with a user definable range from n to m */
  1490. int
  1491. all_args_n2m( int (*action)FUNCARG(long,char*,char*), int dirsflag, int aa_from, int aa_to )
  1492. {
  1493.     int  i;
  1494.     long mask= SCAN_FILE;
  1495.  
  1496.     if( options&1 )
  1497.         mask |= SCAN_RECURSE;
  1498.     if( dirsflag )
  1499.         mask |= SCAN_DIR;
  1500.  
  1501.     for ( i=aa_from; i<aa_to && !dobreak(); ++i)
  1502.         if (isdir(av[i])) {
  1503.             if (options & 1)
  1504.                 newrecurse(mask, av[i], action);
  1505.             if (dirsflag)
  1506.                 (*action)(SCAN_DIR,av[i],av[i]);
  1507.         } else
  1508.             (*action)(SCAN_FILE,av[i],av[i]);
  1509.     if(docr) printf("\n"),docr=0;
  1510.     dobreak();
  1511.     return 0;
  1512. }
  1513.  
  1514. int
  1515. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1516. {
  1517.     return( all_args_n2m(action,dirsflag,1,ac) );
  1518. }
  1519.  
  1520. #define SEARCH_REC   1
  1521. #define SEARCH_CASE  2
  1522. #define SEARCH_WILD  4
  1523. #define SEARCH_NUM   8
  1524. #define SEARCH_EXCL  16
  1525. #define SEARCH_QUIET 32
  1526. #define SEARCH_VERB  64
  1527. #define SEARCH_BIN   128
  1528. #define SEARCH_FILE  256
  1529. #define SEARCH_ABORT 512
  1530. #define SEARCH_LEFT  1024
  1531. #define SEARCH_ONLY  2048
  1532.  
  1533. /* added by amk, not yet implemented */
  1534. #define SEARCH_STYLE 4096    /* alternative style, inspired by GMD */
  1535. #define SEARCH_ONCE  8192    /* only show first pattern match per file */
  1536.  
  1537. static int abort_search;
  1538. static char lowbuf[256], file_name, file_cr;
  1539.  
  1540. static int
  1541. search_file( long mask, char *s, char *fullpath )
  1542. {
  1543.     PATTERN *pat;
  1544.     FILE *fi;
  1545.     char *p, *q;
  1546.     int nocasedep, lctr, len, excl=((options & 16) !=0 ), yesno;
  1547.     char buf[256], searchit[120], first, left;
  1548.  
  1549.     if( abort_search )
  1550.         return 0;
  1551.  
  1552.     nocasedep=!(options & SEARCH_CASE);
  1553.     lctr= docr= file_name= file_cr= 0;
  1554.     if (!(options & (SEARCH_QUIET|SEARCH_FILE))) {
  1555.         if( options & SEARCH_VERB )
  1556.             printf("Examining %s ...\n",fullpath);
  1557.         else
  1558.             printf("\015Examining %s ...\033[K",fullpath), docr=1;
  1559.         fflush( stdout );
  1560.     }
  1561.  
  1562.     strcpy(searchit,searchstring);
  1563.     if (options & SEARCH_WILD) strcat(searchit,"\n");
  1564.     len=strlen(searchit);
  1565.     if (nocasedep) strupr(searchit);
  1566.     first=*searchit;
  1567.  
  1568.     if( strcmp("STDIN",s) && !(options&SEARCH_WILD) && !excl ||
  1569.                  options&SEARCH_BIN )
  1570.         if( quicksearch(s,nocasedep,searchit) )
  1571.             return 0;
  1572.  
  1573.     if( options&SEARCH_BIN )
  1574.         { fprintf(stderr,"Out of memory\n"); return 20; }
  1575.  
  1576.     if(!(pat=compare_preparse( searchit, options&SEARCH_CASE )))
  1577.         { fprintf(stderr,"Invalid pattern\n"); return 20; }
  1578.  
  1579.     fi = strcmp("STDIN",s) ?  fopen(s,"r") : stdin;
  1580.     if (fi==NULL) { pError(s); return 20; }
  1581.  
  1582.     prepscroll(0);
  1583.  
  1584.     while (fgets(buf,256,fi) && !dobreak()) {
  1585.         lctr++; left=1;
  1586.         if (options & SEARCH_WILD)
  1587.             yesno=compare_ok(pat, p=buf);
  1588.         else {
  1589.             if (nocasedep) {
  1590.                 strcpy(lowbuf,buf);
  1591.                 strupr(lowbuf);
  1592.                 p=lowbuf;
  1593.             } else
  1594.                 p=buf;
  1595.             q=p;
  1596.             while ((p=index(p,first)) && strncmp(p++,searchit,len)) ;
  1597.             yesno= (p!=NULL);
  1598.             left = --p - q;
  1599.         }
  1600.         if( yesno ^ excl )
  1601.             if(!(options&SEARCH_ONLY)|| !isalphanum(p[-1])&&!isalphanum(p[len]))
  1602.                 if( found(buf, lctr, 0, s, left ) )
  1603.                     break;
  1604.     }
  1605.     compare_free(pat);
  1606.     if (fi!=stdin) fclose (fi);
  1607.     if( file_cr ) printf("\n");
  1608.     return 0;
  1609. }
  1610.  
  1611. int qcd_flag, qcd_offs;
  1612.  
  1613. #define READCHUNK 60000
  1614.  
  1615. static int
  1616. quicksearch( char *name, int nocasedep, char *pattern )
  1617. {
  1618.     int i, ptrn=strlen(pattern);
  1619.     char ut[256], *buffer, *lend;
  1620.     char *uptab=ut, *get, c, *lpos, *lstart;
  1621.     int len, lnum, qcd=qcd_flag, repeat=(qcd==2 && qcd_offs!=0), buflen;
  1622.     int sofar, got;
  1623.     BPTR fh;
  1624.  
  1625. #ifdef AZTEC_C
  1626.     while(0) while(0) c=c=0, uptab=uptab=ut, get=get=NULL;
  1627. #endif
  1628.  
  1629.     qcd_flag=0;
  1630.     if( !(fh=Open(name,MODE_OLDFILE))) {
  1631.         i=(long)IoErr(), docr=0;
  1632.         printf("\n");
  1633.         ierror(name,i);
  1634.         return 1;
  1635.     }
  1636.     len=filesize( name );
  1637.     buflen=len+3;
  1638.     if( !(buffer=(void *)AllocMem(buflen,0))) { Close(fh); return 0; }
  1639.     sofar=0;
  1640.     do {
  1641.         got=Read( fh, (char *)buffer+sofar, READCHUNK);
  1642.         sofar+=got;
  1643.     } while( got==READCHUNK );
  1644.     Close( fh);
  1645.     if( sofar != len ) {
  1646.         FreeMem( buffer, buflen );
  1647.         pError(pattern); return 1;
  1648.     }
  1649.     if(buffer[len-1]!='\n')
  1650.         buffer[len++]='\n';
  1651.  
  1652.     if( nocasedep )
  1653.         strupr( pattern );
  1654.  
  1655.     if( !qcd )
  1656.         prepscroll(0);
  1657.  
  1658.     for( i=0; i<256; i++ ) uptab[i]=i;
  1659.     if( nocasedep ) for( i='a'; i<='z'; i++ ) uptab[i]=i-'a'+'A';
  1660. retry:
  1661.     c=*pattern, buffer[len]=c, buffer[len+1]=c;
  1662.     get= (qcd==2) ? buffer+qcd_offs : buffer;
  1663.     if( qcd==1 ) qcd_offs=0;
  1664.  
  1665.     lpos=lstart=buffer, lnum=1;
  1666.     for( ;; ) {
  1667.         do ; while( uptab[*get++]!=c );
  1668.         if( --get>=buffer + len )
  1669.             break;
  1670.         for( i=1; i<ptrn; i++ )
  1671.             if( uptab[get[i]]!=pattern[i] )
  1672.                 break;
  1673.         if( i==ptrn ) {
  1674.             for( ;lpos<get; lpos++ )
  1675.                 if( *lpos=='\n' )
  1676.                     lstart=lpos+1, lnum++;
  1677.             for( lend=lstart+1; *lend!='\n'; lend++ ) ;
  1678.             if( qcd ) {
  1679.                 if( get[-1]==':' || get[-1]=='/' ||
  1680.                       lpos==lstart && lend[-1]==':' ) {
  1681.                     char *tmp;
  1682.                     for( tmp=get+ptrn; *tmp&& *tmp!='\n'&& *tmp!='/'; tmp++ );
  1683.                     if( *tmp!='/' ) {
  1684.                         *lend=0;
  1685.                         strncpy(pattern,lstart,79);
  1686.                         qcd_offs=lend-buffer;
  1687.                         FreeMem( buffer, buflen );
  1688.                         return 2;
  1689.                     }
  1690.                 } else 
  1691.                     lend=lpos+1;
  1692.             } else {
  1693.                 *lend=0;
  1694.                 if(!(options&SEARCH_ONLY) ||
  1695.                      !isalphanum(lpos[-1])&&!isalphanum(lpos[ptrn]))
  1696.                     if(found(lstart, lnum, get-buffer, name, lpos==lstart ))
  1697.                         break;
  1698.                 *lend='\n';
  1699.             }
  1700.             get=lend+1;
  1701.         } else
  1702.             get++;
  1703.     }
  1704.     if( repeat )  { repeat=0; qcd_offs=0; goto retry; }
  1705.     if( file_cr ) { printf("\n"); quickscroll(); }
  1706.     FreeMem( buffer, buflen );
  1707.     return 1;
  1708. }
  1709.  
  1710. static int
  1711. found( char *lstart, int lnum, int loffs, char *name, char left )
  1712. {
  1713.     int fileabort=0;
  1714.  
  1715.     if( (options&SEARCH_LEFT) && !left)
  1716.         return 0;
  1717.  
  1718.     if ( docr )
  1719.         { quickscroll(); printf("\n"); docr=0; }
  1720.  
  1721.     if( options&SEARCH_FILE ) {
  1722.         file_cr=1;
  1723.         if( !file_name )
  1724.             printf("%s",name), file_name=1;
  1725.         if( options&SEARCH_NUM )
  1726.             fileabort=1;
  1727.         else
  1728.             printf(" %d",lnum);
  1729.     } else if( options & SEARCH_BIN ) {
  1730.         if (!(options & SEARCH_NUM))
  1731.             printf("Byte offset %d\n",loffs);
  1732.         else
  1733.             printf("%d\n",loffs);
  1734.         quickscroll();
  1735.     } else {
  1736.         if (!(options & SEARCH_NUM))
  1737.             printf("%4d ",lnum);
  1738.         printf((lstart[strlen(lstart)-1]=='\n')?"%s":"%s\n",lstart);
  1739.         quickscroll();
  1740.     }
  1741.     abort_search= options&SEARCH_ABORT;
  1742.     return dobreak() || fileabort || abort_search;
  1743. }
  1744.  
  1745. int
  1746. do_search( void )
  1747. {
  1748.     if(!isconsole(Output())) options |= SEARCH_VERB;
  1749.     abort_search=0;
  1750.     searchstring=av[--ac];
  1751.     all_args(search_file, 0);
  1752.     return 0;
  1753. }
  1754.  
  1755. #if 0
  1756. /* do_grep() is just do_search() with a modified all_args() */
  1757. int
  1758. do_grep( void )
  1759. {
  1760.     if(!isconsole(Output())) options |= SEARCH_VERB;
  1761.     abort_search=0;
  1762.     searchstring=av[1];
  1763.     all_args_n2m(search_file, 0, 2, ac);
  1764.     return 0;
  1765. }
  1766. #endif
  1767.  
  1768. static BOOL rm_error_abort = FALSE;
  1769. static int rm_file( long mask, char *file, char *fullpath )
  1770. {
  1771.     if (rm_error_abort)
  1772.         return(20);
  1773.  
  1774.     if ( *file && file[strlen(file)-1]=='/' ) file[strlen(file)-1]=0;
  1775.     if (options&16 || has_wild) printf(" %s...",fullpath);
  1776.     if (options&2 || options&4) SetProtection(file,0L);
  1777.     if (!DeleteFile(file)) {
  1778.         pError(file);
  1779.         if (options & 8) {
  1780.             rm_error_abort = TRUE;
  1781.             return 20;
  1782.         }
  1783.     } else if (options&16 || has_wild)
  1784.         printf("Deleted\n");
  1785.  
  1786.     return 0;
  1787. }
  1788.  
  1789. int
  1790. do_rm( void )
  1791. {
  1792.     rm_error_abort = FALSE;
  1793.     all_args( rm_file, 1);
  1794.     rm_error_abort = FALSE;
  1795.     return 0;
  1796. }
  1797.  
  1798.  
  1799. int
  1800. do_history( void )
  1801. {
  1802.     HIST *hist;
  1803.     int i = H_tail_base;
  1804.     int len = av[1] ? strlen(av[1]) : 0;
  1805.     char buf[250];
  1806.  
  1807.     if( options&2 ) {
  1808.         while( safegets(buf,stdin) )
  1809.             add_history(buf);
  1810.         return 0;
  1811.     }
  1812.  
  1813.     for (hist = H_tail; hist && !dobreak(); hist = hist->prev, i++)
  1814.         if (len == 0 || !strncmp(av[1], hist->line, len))
  1815.             if( options&1 )
  1816.                 printf("%s\n", hist->line);
  1817.             else
  1818.                 printf("%3d %s\n", i, hist->line);
  1819.     return 0;
  1820. }
  1821.  
  1822. int
  1823. do_mem( void )
  1824. {
  1825.     static long clast, flast;
  1826.     long cfree, ffree, i;
  1827.     char *desc="Free", *mem;
  1828.  
  1829.     if( options&32 )
  1830.         for( i=0; i<10; i++ )
  1831.             if(mem=(char*)AllocMem(0x7fffffff,0))
  1832.                 FreeMem(mem,0x7fffffff);
  1833.  
  1834.     Forbid();
  1835.     cfree = AvailMem (MEMF_CHIP);
  1836.     ffree = AvailMem (MEMF_FAST);
  1837.     Permit();
  1838.     if( options&8 ) {
  1839.         clast=cfree, flast=ffree;
  1840.         return 0;
  1841.     }
  1842.     if( options&16 )
  1843.         cfree=clast-cfree, ffree=flast-ffree, desc="Used";
  1844.     if( options&4 ) {
  1845.         if     ( options & 1 ) printf("%ld\n",cfree);
  1846.         else if( options & 2 ) printf("%ld\n",ffree);
  1847.         else                   printf("%ld\n",cfree+ffree);
  1848.     } else {
  1849.         if     ( options & 1 ) printf("Free CHIP memory:%10s\n",itoa(cfree));
  1850.         else if( options & 2 ) printf("Free FAST memory:%10s\n",itoa(ffree));
  1851.         else {
  1852.             if(ffree) {
  1853.                 printf("FAST memory:%10s\n",itoa(ffree));
  1854.                 printf("CHIP memory:%10s\n",itoa(cfree));
  1855.             }
  1856.             printf("Total  %s:%10s\n",desc,itoa(cfree+ffree));
  1857.         }
  1858.     }
  1859.     return 0;
  1860. }
  1861.  
  1862. int
  1863. do_forline( void )
  1864. {
  1865.     char vname[33], buf[256], *cstr;
  1866.     int lctr;
  1867.     FILE *f;
  1868.  
  1869.     strcpy(vname,av[1]);
  1870.     if( !strcmp(av[2],"STDIN") )
  1871.         f=stdin;
  1872.     else 
  1873.         if(!(f=fopen(av[2],"r"))) { pError(av[2]); return 20; }
  1874.  
  1875.     lctr=0;
  1876.     ++H_stack;
  1877.     cstr = compile_av (av, 3, ac, ' ', 0);
  1878.     while (fgets(buf,256,f) && !dobreak() && !breakcheckd()) {
  1879.         buf[strlen(buf)-1]='\0';    /* remove CR */
  1880.         lctr++;
  1881.         set_var(LEVEL_SET | LEVEL_LOCAL, vname, buf);
  1882.         sprintf(buf,"%d",lctr);
  1883.         set_var(LEVEL_SET | LEVEL_LOCAL, v_linenum, buf);
  1884.         exec_command(cstr);
  1885.     }
  1886.     if( f!=stdin ) fclose(f);
  1887.     --H_stack;
  1888.     free (cstr);
  1889.     if( lctr ) {
  1890.         unset_var (LEVEL_SET, vname);
  1891.         unset_var (LEVEL_SET, v_linenum);
  1892.     }
  1893.     return 0;
  1894. }
  1895.  
  1896. int
  1897. do_fornum( void )
  1898. {
  1899.     char vname[33], buf[16];
  1900.     int n1, n2, step, i=1, verbose, runs=0;
  1901.     char *cstr;
  1902.  
  1903.     verbose=(options & 1);
  1904.     strcpy(vname,av[i++]);
  1905.     n1=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  1906.     n2=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  1907.     if (options & 2) {
  1908.         step=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  1909.     } else
  1910.         step=1;
  1911.     ++H_stack;
  1912.     cstr = compile_av (av, i, ac, ' ', 0);
  1913.     for (i=n1; (step>=0 ? i<=n2 : i>=n2) && !CHECKBREAK() && !breakcheckd();
  1914.          i+=step, runs++) {
  1915.         if (verbose) fprintf(stderr, "fornum: %d\n", i);
  1916.         sprintf(buf,"%d",i);
  1917.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, buf);
  1918.         exec_command(cstr);
  1919.     }
  1920.     --H_stack;
  1921.     free (cstr);
  1922.     if( runs )
  1923.         unset_var (LEVEL_SET, vname);
  1924.     return 0;
  1925. }
  1926.  
  1927. /*
  1928.  * foreach var_name  ( str str str str... str ) commands
  1929.  * spacing is important (unfortunately)
  1930.  *
  1931.  * ac=0    1 2 3 4 5 6 7
  1932.  * foreach i ( a b c ) echo $i
  1933.  * foreach i ( *.c ) "echo -n "file ->";echo $i"
  1934.  */
  1935.  
  1936. int
  1937. do_foreach( void )
  1938. {
  1939.     int cstart, cend;
  1940.     char *cstr, vname[33];
  1941.     char **fav;
  1942.     int i=1, verbose;
  1943.  
  1944.     verbose=(options & 1);
  1945.     strcpy(vname, av[i++]);
  1946.     if (*av[i] == '(') i++;
  1947.     cstart = i;
  1948.     while (i<ac && *av[i] != ')') i++;
  1949.     if (i > ac) { fprintf(stderr,"')' expected\n"); return 20; }
  1950.     ++H_stack;
  1951.     cend = i;
  1952.  
  1953.     fav = (char **)salloc(sizeof(char *) * (ac));
  1954.     for (i = cstart; i < cend; ++i) fav[i] = av[i];
  1955.  
  1956.     cstr = compile_av (av, cend + 1, ac, ' ', 0);
  1957.  
  1958.     for (i = cstart; i<cend && !CHECKBREAK() && !breakcheckd(); ++i) {
  1959.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, fav[i]);
  1960.         if (verbose) fprintf(stderr, "foreach: %s\n", fav[i]);
  1961.         execute(cstr);
  1962.     }
  1963.     --H_stack;
  1964.     free (fav);
  1965.     free (cstr);
  1966.     if( cstart<cend)
  1967.         unset_var (LEVEL_SET, vname);
  1968.     return 0;
  1969. }
  1970.  
  1971. int
  1972. do_forever( char *str )
  1973. {
  1974.     int rcode = 0;
  1975.     char *ptr = next_word( str );
  1976.  
  1977.     ++H_stack;
  1978.     for (;;) {
  1979.         if (CHECKBREAK() || breakcheckd()) { rcode = 20; break; }
  1980.         if (exec_command (ptr) > 0) {
  1981.             str = get_var(LEVEL_SET, v_lasterr);
  1982.             rcode = (str) ? atoi(str) : 20;
  1983.             break;
  1984.         }
  1985.     }
  1986.     --H_stack;
  1987.     return rcode;
  1988. }
  1989.  
  1990. extern struct IntuitionBase *IntuitionBase;
  1991.  
  1992.  
  1993. int
  1994. do_window( void )
  1995. {
  1996.     long x=-1, y=-1, w=-1, h=-1, maxwidth, maxheight, arg[5];
  1997.     int i;
  1998.  
  1999.     if(options & 32) { /* -q */
  2000.         struct Screen *scrn;
  2001.         struct Window *window;
  2002.         ULONG ibase_lock;
  2003.         char **ibase_list=NULL;
  2004.         long i,ibase_num=0;
  2005.         char fmt[256];
  2006.  
  2007.         newwidth(); /* get current window width */
  2008.  
  2009.         ibase_lock = LockIBase(0);
  2010.  
  2011.         for (scrn=IntuitionBase->FirstScreen; scrn; scrn=scrn->NextScreen) {
  2012.  
  2013.             struct List *list;
  2014.             struct Node *node;
  2015.             UBYTE PubNameBuf[MAXPUBSCREENNAME+4] = "";
  2016.  
  2017.             list = LockPubScreenList();
  2018.             for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  2019.                 if (((struct PubScreenNode *)node)->psn_Screen == scrn)
  2020.                     sprintf(PubNameBuf," [%s]",node->ln_Name);
  2021.             }
  2022.             UnlockPubScreenList();
  2023.  
  2024.             sprintf(fmt,"Screen %c%.*s%c%s (%d,%d,%dx%dx%d):\n",
  2025.                 scrn->Title ? '\"' : '(',
  2026.                 (options&64) ? 128 : (((w_width-36-strlen(PubNameBuf)) > 0) ? (w_width-36-strlen(PubNameBuf)) : 30),
  2027.                 scrn->Title ? scrn->Title : "no title",
  2028.                 scrn->Title ? '\"' : ')',
  2029.                 PubNameBuf,
  2030.                 scrn->LeftEdge,
  2031.                 scrn->TopEdge,
  2032.                 scrn->Width,
  2033.                 scrn->Height,
  2034.                 scrn->BitMap.Depth
  2035.             );
  2036.             add_array_list(&ibase_list,&ibase_num,fmt);
  2037.  
  2038.             for (window=scrn->FirstWindow; window; window=window->NextWindow) {
  2039.                 sprintf(fmt,"   win %c%.*s%c (%d,%d,%dx%d)\n",
  2040.                     window->Title ? '\"' : '(',
  2041.                     (options&64) ? 128 : w_width-32,
  2042.                     window->Title ? window->Title : "no title",
  2043.                     window->Title ? '\"' : ')',
  2044.                     window->LeftEdge,
  2045.                     window->TopEdge,
  2046.                     window->Width,
  2047.                     window->Height
  2048.                 );
  2049.                 add_array_list(&ibase_list,&ibase_num,fmt);
  2050.             }
  2051.  
  2052.             if (scrn->NextScreen)
  2053.                 add_array_list(&ibase_list,&ibase_num,"\n");
  2054.         }
  2055.  
  2056.         UnlockIBase(ibase_lock);
  2057.  
  2058.         for(i=0; i<ibase_num; i++)
  2059.             printf("%s",ibase_list[i]);
  2060.  
  2061.         free_array_list(ibase_list,ibase_num);
  2062.  
  2063.         return 0;
  2064.     }
  2065.  
  2066.     if( o_nowindow || !Win )
  2067.         return 20;
  2068.  
  2069.     maxwidth = Win->WScreen->Width;
  2070.     maxheight= Win->WScreen->Height;
  2071.     if( options&1 )
  2072.         x=Win->LeftEdge,y=Win->TopEdge,w=Win->MinWidth,h=Win->MinHeight;
  2073.     if( options&2 ) x=y=0, w=maxwidth, h=maxheight;
  2074.     if( options&4 ) WindowToFront(Win);
  2075.     if( options&8 ) WindowToBack(Win);
  2076.     if( options&16) ActivateWindow(Win);
  2077.     if( ac >= 5) {
  2078.         for(i=1; i<5; i++) {
  2079.             arg[i] = myatoi(av[i],0,1023); if (atoierr) return 20;
  2080.         }
  2081.         x=arg[1]; y=arg[2]; w=arg[3]; h=arg[4];
  2082.     }
  2083.     if( w!=-1 ) {
  2084.         int i;
  2085.         if ( x+w>maxwidth || y+h>maxheight ) {
  2086.             ierror(NULL, 500);
  2087.             return 20;
  2088.         }
  2089.         if( w<Win->MinWidth  ) w=Win->MinWidth;
  2090.         if( h<Win->MinHeight ) h=Win->MinHeight;
  2091.         if( Win->LeftEdge!=0 || Win->TopEdge!=0 )
  2092.             MoveWindow(Win, -Win->LeftEdge, -Win->TopEdge );
  2093.         if( Win->Width!=w || Win->Height!=h )
  2094.             SizeWindow(Win, w-Win->Width   , h-Win->Height  );
  2095.         if( x || y )
  2096.             MoveWindow(Win, x, y );
  2097.         for( i=0; i<10; i++ ) {
  2098.             if(  Win->LeftEdge==x && Win->TopEdge==y && 
  2099.                  Win->Width   ==w && Win->Height ==h )
  2100.                 break;
  2101.             Delay(5);
  2102.         }
  2103.     } else 
  2104.         Delay(20); /* pause 1/2 sec. before trying to print */
  2105.  
  2106.     Delay(10);
  2107.     printf("\014");
  2108.     return 0;
  2109. }
  2110.  
  2111. static void
  2112. setsystemtime(struct DateStamp *ds)
  2113. {
  2114.     struct timerequest tr;
  2115.     long secs= ds->ds_Days*86400+ds->ds_Minute*60+ds->ds_Tick/TICKS_PER_SECOND;
  2116.  
  2117.     if (OpenDevice(TIMERNAME, UNIT_VBLANK,(struct IORequest *)&tr, 0L)) {
  2118.         fprintf(stderr,"Clock error: can't open timer device\n");
  2119.         return;
  2120.     }
  2121.  
  2122.     tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  2123.     tr.tr_node.io_Message.mn_Node.ln_Pri = 0L;
  2124.     tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
  2125.     tr.tr_node.io_Message.mn_ReplyPort = NULL;
  2126.     tr.tr_node.io_Command = TR_SETSYSTIME;
  2127.     tr.tr_time.tv_secs = secs;
  2128.     tr.tr_time.tv_micro = 0L;
  2129.     if (DoIO ((struct IORequest *)&tr))
  2130.         fprintf(stderr,"Clock error: can't talk to timer device\n");
  2131.     CloseDevice ((struct IORequest *)&tr);
  2132. }
  2133.  
  2134. static char tday[LEN_DATSTRING+1];    /* not sure, if +1 (null byte) is neccessary */
  2135.  
  2136. char *
  2137. dates( struct DateStamp *dss, int flags )
  2138. {
  2139.     static char timestr[2*LEN_DATSTRING+1];
  2140.     char tdate[LEN_DATSTRING+1], ttime[LEN_DATSTRING+1];
  2141.     struct DateTime dt;
  2142.     struct DateStamp *myds;
  2143.     char *dp,*tp;
  2144.  
  2145.     dt.dat_Format  = FORMAT_DOS;
  2146.     dt.dat_StrDay  = tday;
  2147.     dt.dat_StrDate = tdate;
  2148.     dt.dat_StrTime = ttime;
  2149.     dt.dat_Flags   = flags ? DTF_SUBST : 0;
  2150.     dt.dat_Stamp   = *dss;
  2151.  
  2152.     myds = &(dt.dat_Stamp);
  2153.  
  2154.     if(  myds->ds_Days<0   || myds->ds_Days>36500 ||
  2155.          myds->ds_Minute<0 || myds->ds_Minute>1440 ||
  2156.          myds->ds_Tick<0   || myds->ds_Tick>3000 || !DateToStr(&dt) )
  2157.         strcpy(tdate,"---------"), strcpy(ttime,"--------");
  2158.  
  2159. #if 0
  2160.     ttime[8] = '\0';
  2161.     sprintf(timestr,"%-9s %-8s",tdate,ttime);
  2162. #endif
  2163.  
  2164.     for (dp=tdate; dp && *dp && (*dp==' ' || *dp=='\t'); dp++)
  2165.         ;
  2166.     for (tp=ttime; tp && *tp && (*tp==' ' || *tp=='\t'); tp++)
  2167.         ;
  2168.     sprintf(timestr,"%9.9s %8.8s",dp,tp);
  2169.  
  2170.     timestr[18] = '\0';    /* protection against bad timestamped files */
  2171.     return timestr;
  2172. }
  2173.  
  2174. /*
  2175.  * returns difference in msecs between two TIMEVALS (GMD)
  2176.  */
  2177.  
  2178. long tv_diff (struct timeval * tv1, struct timeval * tv2)
  2179. {
  2180.     long val;
  2181.  
  2182.     val = ((long) tv2->tv_secs - (long) tv1->tv_secs) * 1000L;
  2183.     val += (((long) tv2->tv_micro) - ((long) tv1->tv_micro)) / 1000L;
  2184.  
  2185.     return val;
  2186. }
  2187.  
  2188. /*
  2189.  * given a DateStamp structure , returns an updated TIMEVAL (GMD)
  2190.  */
  2191.  
  2192. void dss2tv (struct DateStamp * t1, struct timeval * tv)
  2193. {
  2194.     ULONG secs;
  2195.  
  2196.     secs = t1->ds_Days * 24 * 60 * 60;
  2197.     secs += t1->ds_Minute * 60;
  2198.     secs += t1->ds_Tick / TICKS_PER_SECOND;
  2199.  
  2200.     tv->tv_secs = secs;
  2201.     tv->tv_micro = (t1->ds_Tick % TICKS_PER_SECOND) * (1000000 / TICKS_PER_SECOND);
  2202. }
  2203.  
  2204. /*
  2205.  * tv2dss ; converts a timeval structure to a DateStamp structure (GMD)
  2206.  */
  2207.  
  2208. void tv2dss (struct timeval * tv, struct DateStamp * dss)
  2209. {
  2210.     long rem;
  2211.  
  2212.     dss->ds_Days = tv->tv_secs / (24 * 60 * 60);
  2213.     rem = tv->tv_secs % (24 * 60 * 60);    /* secs in last day */
  2214.  
  2215.     dss->ds_Minute = rem / 60;
  2216.     rem = rem % 60;        /* secs in last minute */
  2217.  
  2218.     rem = (rem * 1000) + (tv->tv_micro / 1000);    /* msecs in last minute */
  2219.  
  2220.     dss->ds_Tick = rem / (1000 / TICKS_PER_SECOND);    /* ticks in last minute */
  2221. }
  2222.  
  2223. /* code for battery-clock by Gary Duncan (GMD) */
  2224.  
  2225. int
  2226. do_date (void)
  2227. {
  2228.     static struct DateStamp dss_s; /* set by -s option */
  2229.     static struct timeval tv;
  2230.     struct DateStamp dss;
  2231.     struct DateTime dt;
  2232.     int i = 1;
  2233.  
  2234.     dt.dat_Format = FORMAT_DOS;
  2235.     if (ac == 1) {
  2236.         DateStamp(&dss);
  2237.         if (options & 4) {  /* its read-battery-clock time; GMD */
  2238.             struct timeval tv_batt;
  2239.             if (BattClockBase==NULL) {
  2240.                 fprintf(stderr,"No Battery Clock\n");
  2241.                 return 0;
  2242.             }
  2243.             tv_batt.tv_micro = 0;
  2244.             tv_batt.tv_secs  = ReadBattClock();
  2245.             tv2dss(&tv_batt,&dss);
  2246.         }
  2247.  
  2248.         if (options & 1) {        /* -s option */
  2249.             dss_s = dss;
  2250.             dss2tv(&dss_s,&tv);
  2251.         }
  2252.         else if (options & 2) {        /* -r option */
  2253.             long diff;
  2254.             struct timeval tv1;
  2255.  
  2256.             /*
  2257.              *  if -s not previous done , silently ignore
  2258.              */
  2259.             if (dss_s.ds_Days == 0)
  2260.                 return 0;
  2261.  
  2262.             dss2tv(&dss, &tv1);        /* current time */
  2263.             diff = tv_diff(&tv,&tv1);    /* diff in msecs */
  2264.  
  2265.             printf ("%d.%02d\n", diff / 1000, diff % 1000);
  2266.         }
  2267.         else
  2268.             printf ("%s %s\n", tday, dates (&dss, 0));
  2269.     }
  2270.     else {
  2271.         /* set the time here  */
  2272.         DateStamp (&dt.dat_Stamp);
  2273.         for (; i < ac; i++) {
  2274.             dt.dat_StrDate = NULL;
  2275.             dt.dat_StrTime = NULL;
  2276.             dt.dat_Flags = DTF_FUTURE;
  2277.             if (index (av[i], ':'))
  2278.                 dt.dat_StrTime = av[i];
  2279.             else
  2280.                 dt.dat_StrDate = av[i];
  2281.             if (!StrToDate (&dt))
  2282.                 ierror (av[i], 500);
  2283.         }
  2284.         setsystemtime (&(dt.dat_Stamp));
  2285.     }
  2286.     return 0;
  2287. }
  2288.  
  2289.